#include "stdafx.h"
#include "ReadingInformation.h"
#include <list>
#include <set>
#include <memory>
#include <map>
#include "IReading.h"

#include <iostream>

namespace Sensor {

	
	ReadingInformation::ReadingInformation() {
		readingQueueMutex = CreateMutex(
			nullptr,	// Default security
			false,	// No inital owner
			nullptr	// Unnamed
		);
		if (!readingQueueMutex) {
			std::ostringstream message;
			message << "Error " << GetLastError() << " creating mutex.";
			throw std::exception(message.str().c_str());
		}
		databaseManager.open("database.sqlite", false);
	}

	
	void ReadingInformation::update() {
		// Get a lock on the queue
		DWORD waitResult = WaitForSingleObject( 
			readingQueueMutex,
			INFINITE // No timeout
			);

		// Handle the result of the attempt to wait for the mutex
		if (waitResult == WAIT_OBJECT_0) {
			int readingNumber = readingQueue.size();
			for (int i=0; i<readingNumber; i++) {
				std::unique_ptr<IReading> reading = std::move(readingQueue.front());
				readingQueue.pop();
				std::cout << "ReadingInformation -> " << std::endl;
				std::cout << reading->getRepresentation() << std::endl;

				databaseManager.insertReading(*reading.get());
				lastReadingMap[reading->getType()] = std::move(reading);
			}

			// Release the mutex
			if (!ReleaseMutex(readingQueueMutex)) {
				throw std::exception("Problem encountered while releasing mutex.");
			}
		} else {
			throw std::exception("Problem acquiring mutex.");
		}
	}
	
	std::list<std::unique_ptr<IReading>> ReadingInformation::getReading(const int sensorId, const std::string readingType, const ITime& start, const ITime& end) const {
		return databaseManager.getReadings(sensorId, readingType, start, end);
	}
	
	std::set<std::string> ReadingInformation::getReadingTypes() const {
		return databaseManager.getReadingTypes();
	}

	
	std::set<int> ReadingInformation::getSensorIds(const ITime& start, const ITime& end) const {
		return databaseManager.getSensorIds(start, end);
	}
	
	void ReadingInformation::onReading(unique_ptr<IReading>& reading) {
		// Get a lock on the queue
		DWORD waitResult = WaitForSingleObject( 
			readingQueueMutex,
			INFINITE // No timeout
			);

		// Handle the result of the attempt to wait for the mutex
		switch (waitResult) {
		case WAIT_ABANDONED:
			throw std::exception("Mutex abandoned.");
			break;
		case WAIT_OBJECT_0: // Successfully acquired mutex
			readingQueue.push(std::move(reading));

			// Release the mutex
			if (!ReleaseMutex(readingQueueMutex)) {
				throw std::exception("Problem encountered while releasing mutex.");
			}
			break;
		case WAIT_TIMEOUT:
			throw std::exception("Mutex wait timed out.");
			break;
		case WAIT_FAILED:
			std::ostringstream message;
			message << "Error " << GetLastError() << " waiting for mutex.";
			throw std::exception(message.str().c_str());
			break;
		}
	}

}